package de.mmis.helferlein.demo;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import de.mmis.core.base.Type;
import de.mmis.core.base.abstracttree.Tree;
import de.mmis.core.base.infrastructure.Infrastructure;
import de.mmis.core.base.infrastructure.InfrastructureException;
import de.mmis.core.base.infrastructure.PublishedDeviceDescription;
import de.mmis.core.base.infrastructure.PublishedDeviceDescription.PublishType;
import de.mmis.core.base.util.ClassToXMLConverter;
import de.mmis.core.infrastructure.DistributedInfrastructure;
import de.mmis.core.pojop.NetworkProxy;
import de.mmis.core.sexpression.SExpressionWriter;

public class InformationCollector {

	public static Map<String, Object> collectInformationSocket(String id)
			throws InfrastructureException {

		Infrastructure infrastructure = DistributedInfrastructure
				.createInstance(null);
		ClassLoader classLoader = ClassLoader.getSystemClassLoader();

		HashMap<String, Object> info = new HashMap<String, Object>();
		try {
			info.put("ID", id);
			PublishedDeviceDescription pattern = new PublishedDeviceDescription(
					id, null, PublishType.SOCKET, null, -1);

			// discover the device
			PublishedDeviceDescription device = infrastructure
					.searchSingleDevice(pattern, 1000);
			if (device == null)
				throw new IllegalArgumentException("no object with id=" + id
						+ " has been found by the infrastructure "
						+ infrastructure);
			String host = device.getHost().getHostAddress();
			info.put("host", host);
			int port = device.getPort();
			info.put("port", new Integer(port));

			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			NetworkProxy.getJarData(host, port, baos);

			Type type = NetworkProxy.getDeviceType(host, port, classLoader);
			info.put("type", type);
			info.put("type.abstractName", type.getAbstractName());
			info.put("type.javaClassName", type.getJavaClassName());
			info.put("type.javaClass", type.getJavaClass());

			Map<String, Object> properties = NetworkProxy.getProperties(host,
					port);
			info.put("properties", properties);

			Type[] interfaces = NetworkProxy.getInterfaces(host, port);
			info.put("interfaces", interfaces);

			for (int i = 0; i < interfaces.length; i++) {
				Type ii = interfaces[i];
				info.put("interface." + i + ".abstractName", ii
						.getAbstractName());
				info.put("interface." + i + ".javaClassName", ii
						.getJavaClassName());
				info.put("interface." + i + ".javaClass", ii.getJavaClass());
			}

			// List<Tree> methods = NetworkProxy.getMethods(host, port,
			// classLoader);
			// info.put("methods", methods);

			// for (int i = 0; i < methods.size(); i++) {
			// Tree t = methods.get(i);
			// if (Tree.Type.INNER.equals(t.getType())) {
			// InnerNode method = (InnerNode) t;
			// info.put("method" + i, new String(SExpressionWriter
			// .writeSExpression(method)));
			// }
			// }

			info.put("xml-description", ClassToXMLConverter.toXMLDescription(
					type.getJavaClass(), classLoader));

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return info;
	}

	@SuppressWarnings("unchecked")
	public static String toWikiPage(String id) throws InfrastructureException {
		StringBuilder ret = new StringBuilder();

		Map<String, Object> info = InformationCollector
				.collectInformationSocket("Producer");

		ret.append("\n== Properties of " + id + " ==\n");
		ret.append("* Type: [[" + info.get("type.javaClassName") + "|"
				+ info.get("type.abstractName") + "]]\n");

		// ret.append("=== Publication of " + id + " ===\n");
		//
		// ret.append("* Host: " + info.get("host") + "\n");
		// ret.append("* Port: " + info.get("port") + "\n");

		ret.append("\n=== Additional Properties Attached to " + id + " ===\n");

		Map<String, Object> properties = (Map<String, Object>) info
				.get("properties");
		for (Entry<String, Object> e : properties.entrySet()) {
			ret.append("* [[Property:" + e.getKey() + "|" + e.getKey()
					+ "]] = " + e.getValue() + "\n");
		}

		ret.append("\n== Static Properties of ["
				+ info.get("type.javaClassName") + "] ==\n");

		if (!info.get("type.javaClassName").equals(
				info.get("type.abstractName")))
			ret.append("* Abstract Name: " + info.get("type.abstractName")
					+ "\n");

		ret.append("\n=== Implemented Interfaces === \n");
		Type[] interfaces = (Type[]) info.get("interfaces");
		for (Type interfaze : interfaces)
			ret.append("* [[" + interfaze.getJavaClassName() + "|"
					+ interfaze.getAbstractName() + "]]\n");

		ret.append("\n=== Implemented Methods ===\n");
		List<Tree> methods = (List<Tree>) info.get("methods");
		for (Tree method : methods)
			ret.append("* "
					+ new String(SExpressionWriter.writeSExpression(method))
					+ "\n");

		ret.append("\n=== XML-Description ===\n");
		String xml = (String) info.get("xml-description");
		ret.append(" <nowiki>" + xml.replaceAll("\n", "\n ") + "</nowiki>\n");

		return ret.toString();
	}

	public static void main(String[] args) throws Exception {

		Map<String, Object> info = InformationCollector
				.collectInformationSocket("Producer");
		ArrayList<String> keys = new ArrayList<String>(info.keySet());

		Collections.sort(keys);

		for (String key : keys) {
			System.out.println(key + ":\n    " + info.get(key));
		}

		System.out.println("\n\nWIKIPAGE:\n\n");

		System.out.println(toWikiPage("Producer"));
	}

}
